"""
视频合成热修复补丁 - 不需要 ImageMagick
使用 PIL 在图像上直接绘制字幕

"""

from pathlib import Path
from typing import List, Union
import random
from datetime import timedelta

from tqdm import trange
import numpy as np
import cv2
from PIL import Image, ImageDraw, ImageFont
from moviepy.editor import ImageClip, AudioFileClip, CompositeVideoClip, concatenate_audioclips
import moviepy.video.compositing.transitions as transfx
from moviepy.audio.AudioClip import AudioArrayClip

# ==================== 核心修复：使用 PIL 绘制字幕 ====================

def draw_subtitle_on_image(image_array: np.ndarray, 
                          text: str, 
                          font_size: int = 40,
                          font_color: tuple = (255, 255, 255),
                          bg_color: tuple = (0, 0, 0, 180),
                          position: str = 'bottom') -> np.ndarray:
    """
    使用 PIL 在图像上绘制字幕（不需要 ImageMagick）
    
    Args:
        image_array: 图像数组
        text: 字幕文本
        font_size: 字体大小
        font_color: 字体颜色 (R, G, B)
        bg_color: 背景颜色 (R, G, B, Alpha)
        position: 位置 ('bottom', 'top', 'center')
    
    Returns:
        带字幕的图像数组
    """
    # 转换为 PIL Image
    img = Image.fromarray(image_array)
    width, height = img.size
    
    # 创建绘制对象
    draw = ImageDraw.Draw(img, 'RGBA')
    
    # 尝试加载中文字体
    try:
        # Windows 中文字体路径
        font_paths = [
            r"C:\Windows\Fonts\msyh.ttc",  # 微软雅黑
            r"C:\Windows\Fonts\simhei.ttf",  # 黑体
            r"C:\Windows\Fonts\simsun.ttc",  # 宋体
        ]
        font = None
        for font_path in font_paths:
            if Path(font_path).exists():
                font = ImageFont.truetype(font_path, font_size)
                break
        
        if font is None:
            # 如果没有找到中文字体，使用默认字体
            font = ImageFont.load_default()
    except Exception as e:
        print(f"⚠️ 加载字体失败: {e}，使用默认字体")
        font = ImageFont.load_default()
    
    # 文本换行处理
    max_width = int(width * 0.9)  # 字幕最大宽度为屏幕的90%
    lines = wrap_text(text, font, max_width, draw)
    
    # 计算总高度
    line_height = font_size + 10
    total_text_height = len(lines) * line_height
    padding = 20
    
    # 确定字幕位置
    if position == 'bottom':
        y_start = height - total_text_height - padding * 2
    elif position == 'top':
        y_start = padding
    else:  # center
        y_start = (height - total_text_height) // 2
    
    # 绘制半透明背景
    bg_height = total_text_height + padding * 2
    bg_box = [0, y_start - padding, width, y_start + total_text_height + padding]
    draw.rectangle(bg_box, fill=bg_color)
    
    # 绘制文本（居中对齐）
    for i, line in enumerate(lines):
        # 获取文本边界框
        bbox = draw.textbbox((0, 0), line, font=font)
        text_width = bbox[2] - bbox[0]
        
        x = (width - text_width) // 2
        y = y_start + i * line_height
        
        # 绘制文本阴影（提高可读性）
        shadow_offset = 2
        draw.text((x + shadow_offset, y + shadow_offset), line, 
                 font=font, fill=(0, 0, 0, 255))
        
        # 绘制文本
        draw.text((x, y), line, font=font, fill=font_color + (255,))
    
    # 转换回 numpy 数组
    return np.array(img)


def wrap_text(text: str, font, max_width: int, draw) -> List[str]:
    """文本自动换行"""
    words = text
    lines = []
    current_line = ""
    
    for char in words:
        test_line = current_line + char
        bbox = draw.textbbox((0, 0), test_line, font=font)
        width = bbox[2] - bbox[0]
        
        if width <= max_width:
            current_line = test_line
        else:
            if current_line:
                lines.append(current_line)
            current_line = char
    
    if current_line:
        lines.append(current_line)
    
    return lines


def create_subtitle_clip(image_path: str, 
                        duration: float, 
                        caption: str,
                        fps: int = 10,
                        font_size: int = 40) -> ImageClip:
    """
    创建带字幕的图像剪辑（不需要 ImageMagick）
    
    Args:
        image_path: 图像文件路径
        duration: 持续时间
        caption: 字幕文本
        fps: 帧率
        font_size: 字体大小
    
    Returns:
        带字幕的 ImageClip
    """
    # 读取原始图像
    img = cv2.imread(image_path)
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    
    # 在图像上绘制字幕
    img_with_subtitle = draw_subtitle_on_image(
        img, 
        caption, 
        font_size=font_size,
        position='bottom'
    )
    
    # 创建 ImageClip
    clip = ImageClip(img_with_subtitle)
    clip = clip.set_duration(duration).set_fps(fps)
    
    return clip


# ==================== 修复后的视频合成函数 ====================

def add_zoom_effect(clip, speed=1.0, mode='in', position='center'):
    """缩放效果"""
    fps = clip.fps
    duration = clip.duration
    total_frames = int(duration * fps)
    
    def main(getframe, t):
        frame = getframe(t)
        h, w = frame.shape[:2]
        i = t * fps
        if mode == 'out':
            i = total_frames - i
        zoom = 1 + (i * ((0.1 * speed) / total_frames))
        
        positions = {
            'center': [(w - (w * zoom)) / 2, (h - (h * zoom)) / 2],
            'left': [0, (h - (h * zoom)) / 2],
            'right': [(w - (w * zoom)), (h - (h * zoom)) / 2],
        }
        tx, ty = positions.get(position, positions['center'])
        M = np.array([[zoom, 0, tx], [0, zoom, ty]])
        frame = cv2.warpAffine(frame, M, (w, h))
        return frame
    
    return clip.fl(main)


def add_move_effect(clip, direction="left", move_ratio=0.95):
    """移动效果"""
    orig_width = clip.size[0]
    orig_height = clip.size[1]

    new_width = int(orig_width / move_ratio)
    new_height = int(orig_height / move_ratio)
    clip = clip.resize(width=new_width, height=new_height)

    if direction == "left":
        start_position = (0, 0)
        end_position = (orig_width - new_width, 0)
    else:
        start_position = (orig_width - new_width, 0)
        end_position = (0, 0)

    duration = clip.duration
    moving_clip = clip.set_position(
        lambda t: (start_position[0] + (end_position[0] - start_position[0]) / duration * t,
                   start_position[1])
    )

    final_clip = CompositeVideoClip([moving_clip], size=(orig_width, orig_height))
    return final_clip


def add_slide_effect(clips, slide_duration):
    """滑动转场效果"""
    durations = [clip.duration for clip in clips]
    
    first_clip = CompositeVideoClip(
        [clips[0].fx(transfx.slide_out, duration=slide_duration, side="left")]
    ).set_start(0)

    slide_out_sides = ["left"]
    videos = [first_clip]
    out_to_in_mapping = {"left": "right", "right": "left"}
    
    for idx, clip in enumerate(clips[1:-1], start=1):
        slide_in_side = out_to_in_mapping[slide_out_sides[-1]]
        slide_out_side = "left" if random.random() <= 0.5 else "right"
        slide_out_sides.append(slide_out_side)
        
        videos.append(
            CompositeVideoClip(
                [clip.fx(transfx.slide_in, duration=slide_duration, side=slide_in_side)]
            )
            .set_start(sum(durations[:idx]) - slide_duration * idx)
            .fx(transfx.slide_out, duration=slide_duration, side=slide_out_side)
        )
    
    last_clip = CompositeVideoClip(
        [clips[-1].fx(transfx.slide_in, duration=slide_duration,
                      side=out_to_in_mapping[slide_out_sides[-1]])]
    ).set_start(sum(durations[:-1]) - slide_duration * (len(clips) - 1))
    videos.append(last_clip)

    return CompositeVideoClip(videos)


def compose_video_fixed(story_dir: Union[str, Path],
                        save_path: Union[str, Path],
                        captions: List[str],
                        num_pages: int,
                        fps: int = 10,
                        audio_sample_rate: int = 16000,
                        audio_codec: str = "mp3",
                        caption_config: dict = None,
                        fade_duration: float = 1.0,
                        slide_duration: float = 0.4,
                        zoom_speed: float = 0.5,
                        move_ratio: float = 0.95):
    """
    修复版视频合成 - 不需要 ImageMagick
    使用 PIL 直接在图像上绘制字幕
    """
    if not isinstance(story_dir, Path):
        story_dir = Path(story_dir)

    image_dir = story_dir / "image"
    speech_dir = story_dir / "speech"

    # 检查语音目录
    if not speech_dir.exists():
        print(f"\n⚠️  警告：语音目录不存在: {speech_dir}")
        print("将使用默认时长生成无语音视频")
        use_speech = False
    else:
        use_speech = True

    # 获取字体大小配置
    if caption_config is None:
        caption_config = {}
    font_size = caption_config.get('fontsize', 40)

    video_clips = []

    print("\n" + "="*60)
    print("开始合成视频（修复版 - 使用 PIL 字幕）")
    print("="*60)

    for page in trange(1, num_pages + 1, desc="处理页面"):
        # ========== 1. 处理音频 ==========
        slide_silence = AudioArrayClip(
            np.zeros((int(audio_sample_rate * slide_duration), 2)),
            fps=audio_sample_rate
        )
        fade_silence = AudioArrayClip(
            np.zeros((int(audio_sample_rate * fade_duration), 2)),
            fps=audio_sample_rate
        )

        # 检查语音文件
        speech_file = speech_dir / f"p{page}.wav"
        if use_speech and speech_file.exists():
            speech_clip = AudioFileClip(speech_file.__str__(), fps=audio_sample_rate)
            speech_clip = concatenate_audioclips([fade_silence, speech_clip, fade_silence])
        else:
            # 使用默认时长
            default_duration = 5.0
            silence = AudioArrayClip(
                np.zeros((int(audio_sample_rate * default_duration), 2)),
                fps=audio_sample_rate
            )
            speech_clip = concatenate_audioclips([fade_silence, silence, fade_silence])

        # 添加转场静音
        if page == 1:
            speech_clip = concatenate_audioclips([speech_clip, slide_silence])
        else:
            speech_clip = concatenate_audioclips([slide_silence, speech_clip, slide_silence])

        # ========== 2. 创建带字幕的图像 ==========
        image_file = str(image_dir / f"p{page}.png")
        
        if not Path(image_file).exists():
            print(f"\n❌ 错误：图像文件不存在: {image_file}")
            continue

        # 获取当前页字幕
        caption = captions[page - 1] if page <= len(captions) else ""
        
        # 创建带字幕的图像剪辑
        image_clip = create_subtitle_clip(
            image_file,
            duration=speech_clip.duration,
            caption=caption,
            fps=fps,
            font_size=font_size
        )
        
        # 添加淡入淡出
        image_clip = image_clip.crossfadein(fade_duration).crossfadeout(fade_duration)

        # 随机添加动画效果
        if random.random() <= 0.5:
            zoom_mode = "in" if random.random() <= 0.5 else "out"
            image_clip = add_zoom_effect(image_clip, zoom_speed, zoom_mode)
        else:
            direction = "left" if random.random() <= 0.5 else "right"
            image_clip = add_move_effect(image_clip, direction=direction, move_ratio=move_ratio)

        # 合成视频片段
        video_clip = image_clip.set_audio(speech_clip)
        video_clips.append(video_clip)

    # ========== 3. 添加转场效果 ==========
    print("\n添加滑动转场效果...")
    composite_clip = add_slide_effect(video_clips, slide_duration=slide_duration)

    # ========== 4. 导出视频 ==========
    print(f"\n正在导出视频到: {save_path}")
    composite_clip.write_videofile(
        save_path.__str__(),
        audio_fps=audio_sample_rate,
        audio_codec=audio_codec,
    )

    print("\n" + "="*60)
    print(f"✅ 视频合成完成！")
    print(f"   输出路径: {save_path}")
    print(f"   视频时长: {composite_clip.duration:.2f} 秒")
    print(f"   包含页面: {num_pages} 页")
    print(f"   ✅ 已包含字幕（使用 PIL 绘制）")
    if not use_speech:
        print(f"   ⚠️  注意：未找到语音文件，使用默认时长")
    print("="*60 + "\n")


# ==================== 自动应用补丁 ====================

if __name__ == "__main__":
    """测试或应用补丁"""
    import sys
    
    print("\n" + "="*70)
    print("🔧 视频合成热修复补丁")
    print("="*70)
    
    print("\n此补丁的优势：")
    print("✅ 不需要安装 ImageMagick")
    print("✅ 保留字幕功能（使用 PIL 绘制）")
    print("✅ 支持中文字体")
    print("✅ 自动处理语音文件缺失的情况")
    
    print("\n使用方法：")
    print("1. 保存此文件为: video_compose_hotfix.py")
    print("2. 在 video_compose_agent.py 中导入并使用:")
    print("   from .video_compose_hotfix import compose_video_fixed")
    print("   然后将 compose_video 替换为 compose_video_fixed")
    
    print("\n或者运行测试：")
    print("   python video_compose_hotfix.py test")
    
    if len(sys.argv) > 1 and sys.argv[1] == "test":
        # 简单测试
        print("\n🧪 运行测试...")
        test_image = np.ones((720, 1280, 3), dtype=np.uint8) * 128
        test_result = draw_subtitle_on_image(test_image, "这是测试字幕", font_size=40)
        print("✅ 字幕绘制功能正常")